/**
 * 
 */
package jgrit.options;

import java.awt.event.ActionListener;
import java.util.ArrayList;
import java.util.Collection;

import javax.swing.SwingUtilities;

/**
 * Represents a single option. Should have enough information to create a GUI
 * control.
 * 
 * @author Sam Hartsfield
 */
public class Option {	

	/**
	 * The name of the option. Might be a label in front of a text field or
	 * combo box, or the text on a check box.
	 */
	private String name;
	
	/**
	 * Group/category of the option
	 */
	private String group;
	
	/**
	 * @return the name
	 */
	public String getName() {
		return name;
	}

	/**
	 * @param name the name to set
	 */
	public void setName(String name) {
		this.name = name;
	}

	/**
	 * @return the group
	 */
	public String getGroup() {
		return group;
	}

	/**
	 * @param group the group to set
	 */
	public void setGroup(String group) {
		this.group = group;
	}

	/**
	 * String representation of the current value of the Option; will be
	 * converted to the specific type when necessary.
	 */
	private String value;
	
	/**
	 * Default value of the Option for use when an initial value is not provided
	 * by the caller
	 */
//	private String defaultValue;
	
	private Collection<ActionListener> actionListeners = new ArrayList<ActionListener>();
	
	
	/**
	 * Sets up a new Option. By default, there will be no validation,
	 * so any string will be allowed as a value.
	 * 
	 * @param name The name/label of the option
	 * @param group The group/category that the option is a part of
	 * @param initialValue The initial value of the option
	 */
	public Option(String name, String group, String initialValue) {
		this.name = name;
		this.group = group;
		this.value = initialValue;
	}
	
	/**
	 * Sets the value. If validation fails, then return
	 * false.
	 * 
	 * @param newValue
	 * @return
	 */
	public boolean setValue(String newValue) {
		/**
		 * Fire an action event only if the value changed
		 */
		if (this.value != newValue && this.value == null || newValue == null
				|| !this.value.equals(newValue)) {
			this.value = newValue;
			fireActionEvent();
		}
		return validate();
	}
	
	/**
	 * If your option needs validation (e.g. for a range of integers),
	 * override this method. By default, this will return true for any
	 * value.
	 * 
	 * @return True if the current value is acceptable
	 */
	public boolean validate() {
		return true;
	}
	
	/**
	 * @return True if the char is acceptable
	 */
	public boolean isCharValid(char c) {
		return true;
	}
	
	/**
	 * @return The current value of the Option in String form
	 */
	public String getValue() {
		return value;
	}
	
	/**
	 * @return True if the value is not empty, false otherwise
	 */
	public boolean hasValue() {
		if (value.length() == 0) {
			return false;
		}
		return true;
	}
	
	/**
	 * Run all the listeners when the value is updated. Run on the AWT event
	 * dispatching thread to avoid getting into an undefined state.
	 */
	private void fireActionEvent() {
		SwingUtilities.invokeLater(new Runnable() {
			public void run() {
				for (ActionListener al : actionListeners) {
					al.actionPerformed(null);
				}
			}
		});
	}
	
	public void addActionListener(ActionListener al) {
		actionListeners.add(al);
	}
	
	
}
